﻿using CMS.Infos;
using CMS.REST;
using CMS.Util;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace CMS.Dialogs
{
    public partial class ExportExcelFileDialog : Form
    {
        #region 私有字段
        /// <summary>
        /// 缓存已经加载的课室信息
        /// </summary>
        private Room[] _Rooms = null;

        #endregion

        public ExportExcelFileDialog()
        {
            InitializeComponent();
            TB_Path.Text = Utils.PrivateProfile.ReadString("Export", "Path", "");
        }

        /// <summary>
        /// 在启动时,自动刷新数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ExportExcelFileDialog_Load(object sender, EventArgs e)
        {
            RefreshTermData();
            RefreshRoomData();
        }

        #region 数据刷新函数
        /// <summary>
        /// 刷新学期数据
        /// </summary>
        private void RefreshTermData()
        {
            RESTResponse response = RESTClient.IndexManaged("apis/v1/terms");
            CB_Term.BeginUpdate();
            CB_Term.Items.Clear();
            if (response.IsSuccess)
            {
                CB_Term.Items.AddRange(response.Data.ToObject<Term[]>());
            }
            if (CB_Term.Items.Count > 0)
            {
                CB_Term.SelectedIndex = 0;
            }
            CB_Term.EndUpdate();
        }

        /// <summary>
        /// 刷新课室数据
        /// </summary>
        private void RefreshRoomData()
        {
            RESTResponse response = RESTClient.IndexManaged("apis/v1/room_names");
            CLB_Room.BeginUpdate();
            CLB_Room.Items.Clear();
            if (response.IsSuccess)
            {
                CLB_Room.Items.AddRange(response.Data.ToObject<string[]>());
            }
            CLB_Room.EndUpdate();
            response = RESTClient.IndexManaged("apis/v1/rooms");
            if (response.IsSuccess)
            {
                _Rooms = response.Data.ToObject<Room[]>();
            }
            else
            {
                _Rooms = null;
            }

        }

        /// <summary>
        /// 获取已经选择课室
        /// </summary>
        /// <returns></returns>
        private Room[] _GetSelectedRoom()
        {
            if (_Rooms == null)
            {
                Debug.WriteLine("_Rooms没有数据");
                return null;
            }
            else
            {
                return CLB_Room.CheckedItems.OfType<string>().Join(_Rooms, key => key, room => room.Name, (a, b) => b).ToArray();
            }
        }
        #endregion









        private void Bn_Open_Click(object sender, EventArgs e)
        {
            if (FBD_File.ShowDialog() == DialogResult.OK)
            {
                TB_Path.Text = FBD_File.SelectedPath;
            }
        }

        private void Bn_RefreshTerm_Click(object sender, EventArgs e)
        {
            RefreshTermData();
        }

        private void Bn_RefreshRoom_Click(object sender, EventArgs e)
        {
            RefreshRoomData();
        }

        private void Bn_Start_Click(object sender, EventArgs e)
        {
            ExcelExport export = new ExcelExport();

            if (!Directory.Exists(TB_Path.Text))
            {
                MessageBox.Show(this, "必须选择一个有效的路径存放输出文件");
                return;
            }

            if (CB_Term.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个学期进行导出");
                return;
            }
            Room[] rooms = _GetSelectedRoom();
            if (rooms == null || rooms.Length == 0)
            {
                MessageBox.Show(this, "请至少选择一个课室进行导出");
                return;
            }
            Utils.PrivateProfile.WriteString("Export", "Path", TB_Path.Text);

            Term term = CB_Term.SelectedItem as Term;
            CourseRoom[] courses = new CourseRoom[0];
            RESTResponse response = RESTClient.Index("apis/v1/courses_room", new RESTWhere("term_id", term.ID), new RESTWhere("room", "in", CLB_Room.CheckedItems.OfType<string>()));
            if (response.IsSuccess)
            {
                courses = response.Data.ToObject<CourseRoom[]>();
            }

            if (RB_ExportSchedule.Checked)
            {
                string file = Path.Combine(TB_Path.Text, $"Schedule{DateTime.Now.ToShortTimeString().Replace(":", "")}.{(RB_XLS.Checked ? "xls" : "xlsx")}");
                if (export.ExportScheduleType(file, courses, term, rooms))
                {
                    MessageBox.Show(this, $"保存文件到{file}成功", "保存成功");
                }
            }
            else
            {
                string file = Path.Combine(TB_Path.Text, $"List{DateTime.Now.ToShortTimeString().Replace(":", "")}.{(RB_XLS.Checked ? "xls" : "xlsx")}");
                if (export.ExportListType(file, courses, term, rooms, CB_AutoFill.Checked))
                {
                    MessageBox.Show(this, $"保存文件到{file}成功", "保存成功");
                }
            }
        }


        public class ExcelExport
        {
            private readonly string[] WeekStr = new string[]
            {
                "星期一",
                "星期二",
                "星期三",
                "星期四",
                "星期五",
                "星期六",
                "星期天"
            };

            private readonly string[] TimeStr = new string[]
            {
                "第一二节",
                "第三四节",
                "第五六节",
                "第七八节",
                "第九十节",
                "第1112节",
                "第1314节"
            };

            /// <summary>
            /// 课时表表头
            /// </summary>
            private readonly string[] ListSheetHeader = new string[]
            {
                "星期",
                "课程名称",
                "上课班级",
                "任课老师",
                "上课周次",
                "上课节次",
                "学生人数",
                "机房编号",
                "实验学时",
                "开课学院",
                "备注"
            };

            /// <summary>
            /// 导出课程表
            /// </summary>
            /// <param name="file"></param>
            /// <param name="courses"></param>
            /// <param name="term"></param>
            /// <param name="rooms"></param>
            /// <returns></returns>
            public bool ExportScheduleType(string file, CourseRoom[] courses, Term term, Room[] rooms)
            {
                IWorkbook workbook;
                if (string.Compare(Path.GetExtension(file), ".xls", true) == 0)
                {
                    workbook = new HSSFWorkbook();

                }
                else
                {
                    workbook = new XSSFWorkbook();
                }

                foreach (Room room in rooms)
                {
                    ISheet sheet = workbook.CreateSheet(room.Name);
                    sheet.DefaultColumnWidth = 16;

                    sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, 7));
                    IFont tmpFont = workbook.CreateFont();
                    tmpFont.FontHeightInPoints = 18;
                    tmpFont.FontName = "微软雅黑";

                    ICellStyle tmpStyle = workbook.CreateCellStyle();
                    tmpStyle.VerticalAlignment = VerticalAlignment.Center;
                    tmpStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                    tmpStyle.SetFont(tmpFont);

                    IRow tmpRow = sheet.CreateRow(0);
                    ICell tmpCell = tmpRow.CreateCell(0);
                    tmpCell.SetCellValue($"北京理工大学珠海学院 {room.Name}  教室课表");
                    tmpCell.CellStyle = tmpStyle;


                    tmpFont = workbook.CreateFont();
                    tmpFont.FontHeightInPoints = 12;
                    tmpFont.FontName = "微软雅黑";

                    tmpStyle = workbook.CreateCellStyle();
                    tmpStyle.VerticalAlignment = VerticalAlignment.Center;
                    tmpStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                    tmpStyle.SetFont(tmpFont);

                    sheet.AddMergedRegion(new CellRangeAddress(1, 1, 1, 7));
                    tmpRow = sheet.CreateRow(1);
                    tmpCell = tmpRow.CreateCell(1);
                    tmpCell.SetCellValue($"学年学期:{term.Name}        教室:{room.Name}      所属功能区:机房      所属教学楼:{room.Building}      座位数:{room.SeatCount}");
                    tmpCell.CellStyle = tmpStyle;


                    CourseRoom[] roomCourse = (from course in courses where course.TermID == term.ID && course.Room == room.Name select course).ToArray();

                    tmpFont = workbook.CreateFont();
                    tmpFont.FontHeightInPoints = 8;
                    tmpFont.FontName = "微软雅黑";
                    tmpFont.IsBold = true;

                    tmpStyle = workbook.CreateCellStyle();
                    tmpStyle.VerticalAlignment = VerticalAlignment.Center;
                    tmpStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                    tmpStyle.SetFont(tmpFont);
                    tmpStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;

                    tmpRow = sheet.CreateRow(2);
                    tmpCell = tmpRow.CreateCell(0);
                    tmpCell.CellStyle = tmpStyle;

                    for (int i = 1; i <= 7; i++)
                    {
                        tmpCell = tmpRow.CreateCell(i);
                        tmpCell.SetCellValue(WeekStr[i - 1]);
                        tmpCell.CellStyle = tmpStyle;
                    }

                    tmpFont = workbook.CreateFont();
                    tmpFont.FontHeightInPoints = 8;
                    tmpFont.FontName = "微软雅黑";

                    ICellStyle tmpStyle2 = workbook.CreateCellStyle();
                    tmpStyle2.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                    tmpStyle2.VerticalAlignment = VerticalAlignment.Top;
                    tmpStyle2.SetFont(tmpFont);
                    tmpStyle2.WrapText = true;
                    tmpStyle2.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle2.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle2.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
                    tmpStyle2.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;

                    for (int i = 3; i < 10; i++)
                    {
                        tmpRow = sheet.CreateRow(i);
                        tmpCell = tmpRow.CreateCell(0);
                        tmpCell.SetCellValue(TimeStr[i - 3]);
                        tmpCell.CellStyle = tmpStyle;
                        for (int j = 1; j < 8; j++)
                        {
                            tmpCell = tmpRow.CreateCell(j);

                            int classTime = 3 << ((i - 3) << 1);
                            string[] res = (from course in roomCourse
                                            where j == course.Week && (classTime & course.ClassTimeRaw) != 0
                                            select $"{course.Name}\n{course.ClassName}\n{course.Teacher}\n{course.ClassWeek}周[{course.ClassTime}节]\n人数：{course.StudentCount}\n").ToArray();
                            string value = string.Join("\n", res);
                            tmpCell.SetCellValue(value);
                            tmpCell.CellStyle = tmpStyle2;
                        }
                    }
                    sheet.SetColumnWidth(0, Utils.GetSheetWidth(10));
                }
                while (true)
                {
                    try
                    {
                        using (FileStream fs = new FileStream(file, FileMode.Create))
                        {
                            workbook.Write(fs);
                            return true;
                        }
                    }
                    catch (Exception err)
                    {
                        if (MessageBox.Show($"遇到错误:{err.Message},希望重试吗?", "保存错误", MessageBoxButtons.YesNo) == DialogResult.No)
                        {
                            return false;
                        }
                    }
                }
            }


            /// <summary>
            /// 导出课时表
            /// </summary>
            /// <param name="file"></param>
            /// <param name="courses"></param>
            /// <param name="term"></param>
            /// <param name="rooms"></param>
            /// <param name="autoFill"></param>
            /// <returns></returns>
            public bool ExportListType(string file, CourseRoom[] courses, Term term, Room[] rooms, bool autoFill)
            {
                IWorkbook workbook;
                if (string.Compare(Path.GetExtension(file), ".xls", true) == 0)
                {
                    workbook = new HSSFWorkbook();

                }
                else
                {
                    workbook = new XSSFWorkbook();
                }


                Dictionary<string, Room> studentCountMap = null;
                if (autoFill)
                {
                    studentCountMap = rooms.ToDictionary(r => r.Name);
                }

                ISheet sheet = workbook.CreateSheet();
                IRow tmpRow = sheet.CreateRow(0);
                ICell tmpCell = tmpRow.CreateCell(0);
                ICellStyle tmpStyle = workbook.CreateCellStyle();
                IFont tmpFont = workbook.CreateFont();
                tmpFont.FontHeightInPoints = 18;
                tmpFont.IsBold = true;

                tmpStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                tmpStyle.VerticalAlignment = VerticalAlignment.Center;

                tmpStyle.SetFont(tmpFont);

                sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, 10));

                tmpCell.SetCellValue($"{term.Name}公共机房上机学时");
                tmpCell.CellStyle = tmpStyle;

                tmpFont = workbook.CreateFont();
                tmpFont.FontHeightInPoints = 12;
                tmpFont.IsBold = true;
                tmpStyle = workbook.CreateCellStyle();
                tmpStyle.SetFont(tmpFont);
                tmpStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;

                tmpRow = sheet.CreateRow(1);
                for (int i = 0; i < 11; i++)
                {
                    tmpCell = tmpRow.CreateCell(i);
                    tmpCell.SetCellValue(ListSheetHeader[i]);
                    tmpCell.CellStyle = tmpStyle;
                }


                tmpFont = workbook.CreateFont();
                tmpFont.FontHeightInPoints = 12;
                tmpStyle = workbook.CreateCellStyle();
                tmpStyle.SetFont(tmpFont);
                tmpStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
                tmpStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
                int row = 2;
                foreach (CourseRoom course in courses)
                {
                    tmpRow = sheet.CreateRow(row++);

                    tmpCell = tmpRow.CreateCell(0);
                    tmpCell.SetCellValue(course.Week);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(1);
                    tmpCell.SetCellValue(course.Name);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(2);
                    tmpCell.SetCellValue(course.ClassName);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(3);
                    tmpCell.SetCellValue(course.Teacher);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(4);
                    tmpCell.SetCellValue(course.ClassWeek);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(5);
                    tmpCell.SetCellValue(course.ClassTime);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(6);
                    int studentCount = course.StudentCount <= 0 && autoFill ? (studentCountMap.TryGetValue(course.Room, out Room room) ? room.SeatCount : 0) : course.StudentCount;

                    tmpCell.SetCellValue(studentCount);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(7);
                    tmpCell.SetCellValue(course.Room);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(8);
                    tmpCell.SetCellValue(Utils.CalcBitmapNonZeroCount(course.ClassWeekRaw) * course.TimeSpan);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(9);
                    tmpCell.CellStyle = tmpStyle;

                    tmpCell = tmpRow.CreateCell(10);
                    tmpCell.CellStyle = tmpStyle;
                }

                sheet.SetColumnWidth(0, Utils.GetSheetWidth(5));
                sheet.SetColumnWidth(1, Utils.GetSheetWidth(18));
                sheet.SetColumnWidth(2, Utils.GetSheetWidth(18));
                sheet.SetColumnWidth(3, Utils.GetSheetWidth(12));
                sheet.SetColumnWidth(4, Utils.GetSheetWidth(15));
                sheet.SetColumnWidth(5, Utils.GetSheetWidth(8));
                sheet.SetColumnWidth(6, Utils.GetSheetWidth(8));
                sheet.SetColumnWidth(7, Utils.GetSheetWidth(9));
                sheet.SetColumnWidth(8, Utils.GetSheetWidth(9));
                sheet.SetColumnWidth(9, Utils.GetSheetWidth(20));
                sheet.SetColumnWidth(10, Utils.GetSheetWidth(8));

                while (true)
                {
                    try
                    {
                        using (FileStream fs = new FileStream(file, FileMode.Create))
                        {
                            workbook.Write(fs);
                            return true;
                        }
                    }
                    catch (Exception err)
                    {
                        if (MessageBox.Show($"遇到错误:{err.Message},希望重试吗?", "保存错误", MessageBoxButtons.YesNo) == DialogResult.No)
                        {
                            return false;
                        }
                    }
                }
            }


        }

        private void Bn_SelectAll_Click(object sender, EventArgs e)
        {
            for (int index = 0; index < CLB_Room.Items.Count; index++)
            {
                CLB_Room.SetItemChecked(index, true);
            }
        }

        private void Bn_SelectNone_Click(object sender, EventArgs e)
        {
            for (int index = 0; index < CLB_Room.Items.Count; index++)
            {
                CLB_Room.SetItemChecked(index, false);
            }
        }

        private void label5_Click(object sender, EventArgs e)
        {

        }
    }
}
